from datetime import datetime
from typing import TYPE_CHECKING, Dict, Optional

from sqlalchemy import Boolean, Column, DateTime, Float, ForeignKey, Integer, String, Text, JSON
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func

from app.db.base_class import Base

if TYPE_CHECKING:
    from .contacts import Contact  # noqa: F401
    from .sessions import Session  # noqa: F401


class MessageDirection:
    INCOMING = "incoming"  # 收到的消息
    OUTGOING = "outgoing"  # 发送的消息


class MessageType:
    TEXT = "text"
    IMAGE = "image"
    VOICE = "voice"
    VIDEO = "video"
    FILE = "file"
    LINK = "link"
    LOCATION = "location"
    SYSTEM = "system"
    OTHER = "other"


class MessageStatus:
    SENDING = "sending"  # 正在发送
    SENT = "sent"  # 已发送
    RECEIVED = "received"  # 已接收
    READ = "read"  # 已读
    PENDING = "pending"  # 等待发送
    FAILED = "failed"  # 发送失败
    RECALLED = "recalled"  # 已撤回
    ERROR = "error"  # 错误状态


class Message(Base):
    """消息记录表"""
    id = Column(Integer, primary_key=True, index=True)
    contact_id = Column(Integer, ForeignKey("contact.id"), nullable=True, comment="联系人ID")
    session_id = Column(Integer, ForeignKey("session.id"), nullable=False, comment="会话ID")
    direction = Column(
        String(10), 
        nullable=False, 
        default=MessageDirection.INCOMING, 
        comment="消息方向: incoming/outgoing"
    )
    msg_type = Column(
        String(20), 
        nullable=False, 
        default=MessageType.TEXT, 
        comment="消息类型: text/image/voice/video/file/link/location/system/other"
    )
    content = Column(String(2000), nullable=False, comment="消息内容")
    sent_at = Column(DateTime, nullable=False, default=func.now(), comment="发送时间")
    status = Column(
        String(10), 
        nullable=False, 
        default=MessageStatus.RECEIVED, 
        comment="消息状态: sending/sent/received/read/pending/failed/recalled/error"
    )
    extra_data = Column(JSON, nullable=True, comment="额外数据, JSON格式")
    
    created_at = Column(DateTime, nullable=False, default=func.now(), comment="创建时间")
    updated_at = Column(
        DateTime, 
        nullable=False, 
        default=func.now(), 
        onupdate=func.now(), 
        comment="更新时间"
    )
    
    # 媒体文件相关字段
    media_path = Column(String(500), nullable=True, comment="媒体文件本地路径")
    media_type = Column(String(20), nullable=True, comment="媒体文件类型")
    media_size = Column(Integer, nullable=True, comment="媒体文件大小(字节)")
    media_name = Column(String(255), nullable=True, comment="媒体文件名称")
    
    # PUA检测相关
    pua_score = Column(Float, nullable=True, comment="PUA评分(0-1之间，越高越可能是PUA)")
    pua_patterns = Column(Text, nullable=True, comment="检测到的PUA模式(JSON格式)")
    
    # 关系
    contact = relationship("Contact", back_populates="messages", lazy="joined")
    session = relationship("Session", back_populates="messages", lazy="joined")
    
    def __repr__(self):
        return f"<Message {self.id}: {self.content[:20]}>"
    
    def to_dict(self):
        """转换为字典"""
        extra_data = {}
        if self.extra_data:
            if isinstance(self.extra_data, str):
                try:
                    extra_data = json.loads(self.extra_data)
                except:
                    extra_data = {"raw": self.extra_data}
            else:
                extra_data = self.extra_data
        
        result = {
            "id": self.id,
            "contact_id": self.contact_id,
            "session_id": self.session_id,
            "direction": self.direction,
            "msg_type": self.msg_type,
            "content": self.content,
            "sent_at": self.sent_at.isoformat() if self.sent_at else None,
            "status": self.status,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
            "contact": self.contact.to_dict() if self.contact else None,
            "session": self.session.to_dict() if self.session else None,
            "extra_data": extra_data
        }
        
        # 添加媒体文件信息
        if self.has_media():
            media_info = self.media_info()
            result.update({
                "media_info": media_info
            })
            
        # 添加语音识别结果
        if self.msg_type == MessageType.VOICE:
            speech_text = self.get_speech_to_text()
            if speech_text:
                result.update({
                    "speech_to_text": speech_text
                })
            
        return result
    
    def has_media(self) -> bool:
        """是否包含媒体文件"""
        return self.msg_type in [MessageType.IMAGE, MessageType.FILE, MessageType.VOICE, MessageType.VIDEO]
    
    def media_info(self) -> Dict:
        """获取媒体文件信息"""
        if not self.has_media():
            return {}
            
        try:
            # 尝试从extra_data获取媒体信息
            extra_data = {}
            if self.extra_data:
                if isinstance(self.extra_data, str):
                    extra_data = json.loads(self.extra_data)
                else:
                    extra_data = self.extra_data
                    
            # 获取媒体路径
            media_path = extra_data.get("media_local_path")
            if not media_path and "media" in extra_data and isinstance(extra_data["media"], dict):
                media_path = extra_data["media"].get("path")
                
            # 获取媒体文件名
            media_filename = extra_data.get("media_filename")
            if not media_filename and "media" in extra_data and isinstance(extra_data["media"], dict):
                media_filename = extra_data["media"].get("filename")
                
            # 获取文件大小
            media_size = extra_data.get("media_size")
            if not media_size and "media" in extra_data and isinstance(extra_data["media"], dict):
                media_size = extra_data["media"].get("size")
                
            # 判断文件是否可用
            media_available = False
            if media_path and os.path.exists(media_path):
                media_available = True
                
            return {
                "path": media_path,
                "filename": media_filename,
                "size": media_size,
                "available": media_available,
                "type": self.msg_type
            }
            
        except Exception as e:
            logging.error(f"获取媒体文件信息失败: {str(e)}")
            return {"error": str(e)}
    
    def get_speech_to_text(self) -> Optional[str]:
        """获取语音转文字内容"""
        if self.msg_type != MessageType.VOICE:
            return None
            
        try:
            # 尝试从extra_data获取语音转文字结果
            extra_data = {}
            if self.extra_data:
                if isinstance(self.extra_data, str):
                    extra_data = json.loads(self.extra_data)
                else:
                    extra_data = self.extra_data
            
            # 首先检查是否成功转换
            if extra_data.get("speech_to_text_success") and extra_data.get("speech_to_text"):
                return extra_data["speech_to_text"]
                
            # 如果没有直接的转换结果字段，尝试从content中提取
            if self.content and self.content.strip().startswith("[语音]"):
                text_content = self.content.strip()[4:].strip()  # 去掉[语音]前缀
                if text_content:
                    return text_content
                    
            return None
            
        except Exception as e:
            logging.error(f"获取语音转文字内容失败: {str(e)}")
            return None
    
    def is_media_available(self) -> bool:
        """媒体文件是否可用"""
        media_info = self.media_info()
        return media_info.get("available", False)
        
    def get_media_path(self) -> Optional[str]:
        """获取媒体文件路径"""
        media_info = self.media_info()
        return media_info.get("path")